#ifndef BONUS_H
#define BONUS_H


#include "dtwenty_global.h"
#include "dtwentyitem.h"


#include <QObject>
#include <QSharedData>
#include <QExplicitlySharedDataPointer>

#include <QMetaObject>
#include <QMetaEnum>


class DTWENTYSHARED_EXPORT CategoryBase : public DTwentyItem
{
    Q_OBJECT

    class Data : public QSharedData
    {
    public:
        Data()
        {
            category = 0;
        }

        Data(const Data& other) : QSharedData(other)
        {
            category = other.category;
        }

        QVariant category;

    };

    Q_PROPERTY(QVariant category READ category WRITE setCategory)


public:

    CategoryBase(QObject *parent = 0);
    CategoryBase(const QString& name, QObject *parent = 0);
    CategoryBase(const CategoryBase& other);

    QVariant category() const;

    virtual QVariantMap categories() const;
    virtual QVariant value(const QVariant& from = QVariant()) const = 0;


public slots:

    void setCategory(const QVariant& category) const;


protected:

    template <typename CATEGORY_TYPE>
    static QVariantMap enumCategories()
    {
        int offset = CATEGORY_TYPE::staticMetaObject.enumeratorOffset();
        if (offset <= 0)
        {
            return QVariantMap();
        }

        QVariantMap ret;

        QMetaEnum me = CATEGORY_TYPE::staticMetaObject.enumerator(offset);
        QString name = me.name();
        for (int i = 0; i < me.keyCount(); i++)
        {
            QString key = me.key(i);
            if (key.startsWith(name))
            {
                key = key.remove(0, name.count());
            }

            ret.insert(key, me.value(i));
        }

        return ret;
    }


private:

    QExplicitlySharedDataPointer<Data> d;


};


class DTWENTYSHARED_EXPORT BaseAttackBonus : public CategoryBase
{
    Q_OBJECT

public:

    enum Category
    {
        Category_Poor = 0,
        Category_Normal,
        Category_Good
    };

    Q_ENUMS(Category)

    Q_INVOKABLE BaseAttackBonus(QObject* parent = 0) :
        CategoryBase(tr("Base Attack"), parent)
    {
    }

    virtual QVariant value(const QVariant &from) const
    {
        if (category().isNull() || from.isNull())
        {
            return QVariant();
        }

        int level = from.toInt();

        switch (category().toInt())
        {
        case Category_Good:
            return level;

        case Category_Normal:
            return (level-1) - ((level-1)/4);

        case Category_Poor:
            return (level-1)/2;

        default:
            break;
        }
        return QVariant();
    }

    virtual QVariantMap categories() const
    {
        return enumCategories<BaseAttackBonus>();
    }

};

Q_DECLARE_METATYPE(BaseAttackBonus)

class DTWENTYSHARED_EXPORT SaveBonus : public CategoryBase
{
    Q_OBJECT

public:

    enum Category
    {
        Category_Normal = 0,
        Category_Good
    };

    Q_ENUMS(Category)

    Q_INVOKABLE SaveBonus(const QString& name = QString(), QObject* parent = 0) :
        CategoryBase(name, parent)
    {
    }

    virtual QVariant value(const QVariant &from) const
    {
        if (category().isNull() || from.isNull())
        {
            return QVariant();
        }

        int level = from.toInt();

        switch (category().toInt())
        {
        case Category_Normal:
            return (level/3);

        case Category_Good:
            return (level/2)+2;

        default:
            break;
        }

        return QVariant();
    }


    virtual QVariantMap categories() const
    {
        return enumCategories<SaveBonus>();
    }
};

Q_DECLARE_METATYPE(SaveBonus)

class DTWENTYSHARED_EXPORT HitDie : public CategoryBase
{
    Q_OBJECT

public:

    enum Category
    {
        Category_D4 = 4,
        Category_D6 = 6,
        Category_D8 = 8,
        Category_D10 = 10,
        Category_D12 = 12
    };

    Q_ENUMS(Category)

    Q_INVOKABLE HitDie(QObject* parent = 0) :
        CategoryBase(tr("Hit Die"), parent)
    {
    }

    virtual QVariant value(const QVariant &from = QVariant()) const
    {
        return from;
    }

    virtual QVariantMap categories() const
    {
        return enumCategories<HitDie>();
    }
};

Q_DECLARE_METATYPE(HitDie)

class DTWENTYSHARED_EXPORT SkillPoints : public CategoryBase
{
    Q_OBJECT

public:

    enum Category
    {
        Category_Uneducated = 2,
        Category_Skilled = 4,
        Category_Expert = 6,
        Category_Master = 8
    };

    Q_ENUMS(Category)

    Q_INVOKABLE SkillPoints(QObject* parent = 0) :
        CategoryBase(tr("Skill Points"), parent)
    {
    }

    virtual QVariant value(const QVariant &from = QVariant()) const
    {
        return from;
    }

    virtual QVariantMap categories() const
    {
        return enumCategories<SkillPoints>();
    }
};

Q_DECLARE_METATYPE(SkillPoints)


#endif // BONUS_H
